/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */
#include "at32f421_gpio.h"
#include <stdbool.h>
#include "rtthread.h"
#include "rgb.h"

#define DBG_TAG "pwr"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#define ORDINARY_CHANNEL_NUM 7
// PA0 ADC_IN0
// PA1 ADC_IN1
// PA5 PWR_ON_OFF
// PB2 5V_EN
// PB10 PWR_KEY
// PA15 ADC_EN

static bool powrOnFlag = 0;
static uint8_t current_channel = 0;
static uint16_t adc1_ordinary_valuetab[ORDINARY_CHANNEL_NUM] = {0};
static uint16_t cell1_vol = 0;
static uint16_t cell2_vol = 0;
static uint16_t bat_vol = 0;
const uint16_t channel_list[ORDINARY_CHANNEL_NUM] = {
    ADC_CHANNEL_0,
    ADC_CHANNEL_1,
    ADC_CHANNEL_11,
    ADC_CHANNEL_12,
    ADC_CHANNEL_15, // VSS
    ADC_CHANNEL_16, // TEMP
    ADC_CHANNEL_17, // REF
};
bool isPowerOn(void)
{
    return powrOnFlag;
}
void pwr_init(void)
{
    gpio_init_type gpio_init_struct;
    crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);

    /* ADC0~1 -> PA0,PA1, ADC11,12->PB11,PB12 pin initialize */
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode = GPIO_MODE_ANALOG;
    gpio_init_struct.gpio_pins = GPIO_PINS_0 | GPIO_PINS_1;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init(GPIOA, &gpio_init_struct);
    gpio_init_struct.gpio_pins = GPIO_PINS_12 | GPIO_PINS_13;
    gpio_init(GPIOB, &gpio_init_struct);

    /**PWR_EN -> PA5, ADC_EN -> PA15*/
    gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
    gpio_init_struct.gpio_pins = GPIO_PINS_5 | GPIO_PINS_15;
    gpio_init(GPIOA, &gpio_init_struct);
    /**5V_EN -> PB8*/
    gpio_init_struct.gpio_pins = GPIO_PINS_8;
    gpio_init(GPIOB, &gpio_init_struct);
    /**PWR_KEY -> PB10, RST_KEP PB0*/
    gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
    gpio_init_struct.gpio_pull = GPIO_PULL_UP;
    gpio_init_struct.gpio_pins = GPIO_PINS_10 | GPIO_PINS_0;
    gpio_init(GPIOB, &gpio_init_struct);

    gpio_bits_set(GPIOA, GPIO_PINS_10);
    gpio_bits_set(GPIOB, GPIO_PINS_0);
}
void hardware_power_on(confirm_state newstate)
{
    if (newstate)
    {
        gpio_bits_set(GPIOA, GPIO_PINS_5);
    }
    else
    {
        gpio_bits_reset(GPIOA, GPIO_PINS_5);
    }
}
// 函数：硬件5V开关
// 参数：confirm_state newstate，表示开关状态
void hardware_5v_on(confirm_state newstate)
{
    // 如果开关状态为开
    if (newstate)
    {
        // 设置GPIOB的2号引脚为高电平
        gpio_bits_set(GPIOB, GPIO_PINS_8);
    }
    // 如果开关状态为关
    else
    {
        // 设置GPIOB的2号引脚为低电平
        gpio_bits_reset(GPIOB, GPIO_PINS_8);
    }
}
void hardware_adc_on(confirm_state newstate)
{
    if (newstate)
    {
        gpio_bits_set(GPIOA, GPIO_PINS_15);
    }
    else
    {
        gpio_bits_reset(GPIOA, GPIO_PINS_15);
    }
}
uint8_t hardware_is_pwrkey_trig(void)
{
    return (gpio_input_data_bit_read(GPIOB, GPIO_PINS_10) == 0);
}
uint8_t hardware_is_rstkey_trig(void)
{
    return (gpio_input_data_bit_read(GPIOB, GPIO_PINS_0) == 0);
}
uint16_t get_battery_voltage(uint16_t *cell1, uint16_t *cell2)
{
    hardware_adc_on(TRUE);

    return 0;
}

void adc_dma_config(void)
{
    dma_init_type dma_init_struct;
    crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
    //   nvic_irq_enable(DMA1_Channel1_IRQn, 0, 0);
    dma_reset(DMA1_CHANNEL1);
    dma_default_para_init(&dma_init_struct);
    dma_init_struct.buffer_size = 2;
    dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_base_addr = (uint32_t)adc1_ordinary_valuetab;
    dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
    dma_init_struct.memory_inc_enable = TRUE;
    dma_init_struct.peripheral_base_addr = (uint32_t)&(ADC1->odt);
    dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
    dma_init_struct.peripheral_inc_enable = FALSE;
    dma_init_struct.priority = DMA_PRIORITY_HIGH;
    dma_init_struct.loop_mode_enable = TRUE;
    dma_init(DMA1_CHANNEL1, &dma_init_struct);

    //   dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
    dma_channel_enable(DMA1_CHANNEL1, TRUE);
}
void adc_config(void)
{
    adc_base_config_type adc_base_struct;
    crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);
    crm_adc_clock_div_set(CRM_ADC_DIV_16);

    adc_base_default_para_init(&adc_base_struct);
    adc_base_struct.sequence_mode = TRUE;
    adc_base_struct.repeat_mode = TRUE;
    adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
    adc_base_struct.ordinary_channel_length = 1;
    adc_base_config(ADC1, &adc_base_struct);
    adc_ordinary_channel_set(ADC1, ADC_CHANNEL_0, 1, ADC_SAMPLETIME_239_5);
    // adc_ordinary_channel_set(ADC1, ADC_CHANNEL_1, 2, ADC_SAMPLETIME_239_5);
    // adc_ordinary_channel_set(ADC1, ADC_CHANNEL_11, 3, ADC_SAMPLETIME_239_5);
    // adc_ordinary_channel_set(ADC1, ADC_CHANNEL_12, 4, ADC_SAMPLETIME_239_5);

    // adc_ordinary_channel_set(ADC1, ADC_CHANNEL_6, 3, ADC_SAMPLETIME_239_5);

    adc_ordinary_conversion_trigger_set(ADC1, ADC12_ORDINARY_TRIG_SOFTWARE, TRUE);
    // adc_dma_mode_enable(ADC1, TRUE);

    adc_enable(ADC1, TRUE);
    adc_calibration_init(ADC1);
    while (adc_calibration_init_status_get(ADC1))
        ;
    adc_calibration_start(ADC1);
    while (adc_calibration_status_get(ADC1))
        ;
    adc_ordinary_software_trigger_enable(ADC1, TRUE);
}
struct pwr_key
{
    uint8_t down : 1;
    uint8_t long_press : 1;
    uint8_t hold : 2;
    uint8_t cnt : 4;
    uint8_t interval;
} pwr_key_status;
void pwr_key_monitor(void)
{
    // FIXME Hardware error!

    if (hardware_is_pwrkey_trig())
    {
        if (pwr_key_status.hold < 2) // 2x20=40ms
        {
            pwr_key_status.hold++;
        }
        else
        {
            pwr_key_status.down = 1;
            pwr_key_status.interval = 100;//20x100 = 200ms
        }
    }
    else
    {
        pwr_key_status.hold = 0;
        if (pwr_key_status.down)
        {
            if (pwr_key_status.cnt < 0x0f)
            {
                pwr_key_status.cnt++;
            }
            pwr_key_status.down = 0;
        }
        if (pwr_key_status.interval != 0)
        {
            pwr_key_status.interval--;
            if (pwr_key_status.interval == 0)
            {
                rt_kprintf("pwrkey:%d\n", pwr_key_status.cnt);
                pwr_key_status.cnt = 0;
            }
        }
    }
}
void batteryVolateMonitor(void)
{
    // adc_ordinary_software_trigger_enable(ADC1, TRUE);
    if (adc_flag_get(ADC1, ADC_CCE_FLAG) != RESET)
    {
        adc_flag_clear(ADC1, ADC_CCE_FLAG);
        // dma_flag_clear(DMA1_FDT1_FLAG);
        // rt_kprintf("adcValue:%04d %04d\r\n", adc1_ordinary_valuetab[0], adc1_ordinary_valuetab[1]);
        cell1_vol = (float)adc1_ordinary_valuetab[0] * 1.20849609375f; // x3300/4096/(2/3)
        bat_vol = (float)adc1_ordinary_valuetab[1] * 2.4169921875f;  // x3300/4096/(1/3)
        cell2_vol = bat_vol - cell1_vol;
        adc1_ordinary_valuetab[current_channel] = adc_ordinary_conversion_data_get(ADC1);
        current_channel++;
        if (current_channel >= ORDINARY_CHANNEL_NUM)
        {
            current_channel = 0;
        }
        adc_ordinary_channel_set(ADC1, channel_list[current_channel], 1, ADC_SAMPLETIME_239_5);
        // rt_kprintf("cell1:%d cell2:%d bat:%d\r\n", cell1_vol, cell2_vol, bat_vol);

        // rt_kprintf("ADC:%d, %d, %d, %d, %d, %d, %d\r\n", adc1_ordinary_valuetab[0], adc1_ordinary_valuetab[1], adc1_ordinary_valuetab[2], adc1_ordinary_valuetab[3],
        //     adc1_ordinary_valuetab[4], adc1_ordinary_valuetab[5], adc1_ordinary_valuetab[6]);

        adc_ordinary_software_trigger_enable(ADC1, TRUE);
    }
}
void powerOnSeq(void)
{
    static uint16_t pwrKeyHoldCnt = 0;

    if (!isPowerOn())
    {
        if (hardware_is_pwrkey_trig())
        {
            if (pwrKeyHoldCnt < 333)
            {
                pwrKeyHoldCnt++;
                rgb_set(255, 255, 255);
            }
            else
            {
                hardware_5v_on(1);
                rgb_set(0, 255, 0);
                hardware_power_on(1);
            }
        }
        else
        {
            if (pwrKeyHoldCnt >= 333)
            {
                hardware_adc_on(1);
                hardware_5v_on(1);
                powrOnFlag = 1;
                rt_kprintf("power on\r\n");
            }
            pwrKeyHoldCnt = 0;
        }
    }
    else
    {
        pwrKeyHoldCnt = 0;
    }
}
void powerOffSeq(void)
{
    static uint16_t pwrKeyHoldCnt = 0;
    if (isPowerOn() && rt_tick_get() > 3000)
    {
        if (hardware_is_pwrkey_trig())
        {
            if (pwrKeyHoldCnt <= 1000)
            {
                pwrKeyHoldCnt++;
                rgb_set(255, 255, 255);
            }
            else
            {
                rgb_set(0, 0, 0);
                hardware_adc_on(0);
                hardware_5v_on(0);
            }
        }
        else
        {
            if (pwrKeyHoldCnt >= 1000)
            {

                powrOnFlag = 0;
                rt_kprintf("power off\r\n");
                hardware_power_on(0);
            }
            pwrKeyHoldCnt = 0;
        }
    }
    else
    {
        pwrKeyHoldCnt = 0;
    }
}
/**
 * @brief monitor battery voltage and pwrKey action
 *
 */
void pwr_task(void *param)
{

    pwr_init();
    // adc_dma_config();
    adc_config();
    // hardware_adc_on(1);
    // hardware_power_on(1);
    // hardware_5v_on(1);

    rt_kprintf("pwr task start\r\n");
    // rt_kprintf(" adc on \n");
    // rt_kprintf(" power on \n");
    // rt_kprintf(" 5v on \n");

    while (1)
    {
        /**power on sequency */
        powerOnSeq();
        /**power off sequency */
        powerOffSeq();
        /**keyAction monitor */
        pwr_key_monitor();

        /**batteryVoltage monitor */
        batteryVolateMonitor();

        rt_thread_mdelay(3);
    }
}

#define PWR_STATCK_SIZE 150
ALIGN(8)
static rt_uint8_t pwr_stack[PWR_STATCK_SIZE];
struct rt_thread pwr_thread;

int pwr_task_lanuch(void)
{
    rt_thread_t tid = &pwr_thread;
    rt_err_t result = rt_thread_init(tid, "pwr", pwr_task, RT_NULL,
                                     pwr_stack, sizeof(pwr_stack), 0, 20);
    if (result == RT_EOK)
    {
        rt_thread_startup(tid);
    }
    else
    {
        rt_kprintf("pwr thread create failed\r\n");
    }
    return 0;
}
INIT_APP_EXPORT(pwr_task_lanuch);

#include <stdlib.h>
void pwr(int argc, char **argv)
{
    rt_kprintf("Cell[0]:%0dmV Cell[1]:%dmV Bat:%dmV\r\n", cell1_vol, cell2_vol, bat_vol);
}
MSH_CMD_EXPORT(pwr, pwr);
